using System;
using System.Reflection;
using HeadFirstDesignPatterns.Proxy.Dynamic.Net;
using NUnit.Framework;

namespace HeadFirstDesignPatterns.DeveloperTests.Proxy.Dynamic.Net
{
	/// <summary>
	/// ProxyDynamicNetFixture tests the proxy dynamic pattern
	/// </summary>
	[TestFixture]
	public class ProxyDynamicFixture
	{
		#region TestProxyOwner
		[Test]
		public void TestProxyOwner()
		{			
			Person person = new Person();
			IPerson personProxy = (IPerson)DynamicProxyFactory.Instance.CreateProxy(person, new InvocationDelegate(OwnerInvocationHandler));
			
			personProxy.Gender = "Male";
			personProxy.Name = "John Doe";
			personProxy.Interest = "Eating junkfood and watching talkshows";
			Assert.AreEqual("Name: John Doe","Name: " + person.Name);
			Assert.AreEqual("Gender: Male","Gender: " + person.Gender);
			Assert.AreEqual("Interest: Eating junkfood and watching talkshows",
				"Interest: " + person.Interest);

//			Console.WriteLine("Name: " + person.Name);
//			Console.WriteLine("Gender: " + person.Gender);
//			Console.WriteLine("Interest: " + person.Interest);
		}
		#endregion//TestProxyOwner

		#region TestProxyOwnerException
		[Test]
		[ExpectedException(typeof(UnauthorizedAccessException))]
		public void TestProxyOwnerException()
		{			
			Person person = new Person();
			IPerson personProxy = (IPerson)DynamicProxyFactory.Instance.CreateProxy(person, new InvocationDelegate(OwnerInvocationHandler));
			
			personProxy.Name = "John Doe";
			personProxy.HotOrNot = 10;
			
			Console.WriteLine("Name: " + person.Name);
			Console.WriteLine("Rating: " + person.HotOrNot);

		}
		#endregion//TestProxyOwnerException

		#region TestProxyNonOwnerSetRating
		[Test]
		public void TestProxyNonOwnerSetRating()
		{			
			Person person = new Person();
			person.Name = "John Doe";

			IPerson personProxy = (IPerson)DynamicProxyFactory.Instance.CreateProxy(person, new InvocationDelegate(NonOwnerInvocationHandler));
			
			personProxy.HotOrNot = 10;
			personProxy.HotOrNot = 5;
			
			Assert.AreEqual("Name: John Doe","Name: " + person.Name);
			Assert.AreEqual("Rating: 7","Rating: " + person.HotOrNot);

//			Console.WriteLine("Name: " + person.Name);
//			Console.WriteLine("Rating: " + person.HotOrNot);
		}
		#endregion//TestProxyNonOwnerSetRating

		#region TestProxyNonOwnerException
		[Test]
		[ExpectedException(typeof(UnauthorizedAccessException))]
		public void TestProxyNonOwnerException()
		{			
			Person person = new Person();
			person.Name = "John Doe";

			IPerson personProxy = (IPerson)DynamicProxyFactory.Instance.CreateProxy(person, new InvocationDelegate(NonOwnerInvocationHandler));
			
			personProxy.Name = "John Doe";
			personProxy.Interest = "This will not display due to exception";		
			
			Console.WriteLine("Name: " + person.Name);
			Console.WriteLine("Interest: " + person.Interest);
		}
		#endregion//TestProxyNonOwnerException

		#region OwnerInvocationHandler
		private object OwnerInvocationHandler(object target, MethodBase method, object[] parameters) 
		{
			object result = null;

			try
			{
				if(!method.Name.Equals("set_HotOrNot"))
				{
					result = method.Invoke(target, parameters);
				}
				else
				{
					throw new UnauthorizedAccessException("You are not permitted to rate yourself");
				}
			}
			catch(ApplicationException ex)
			{
				return ex.StackTrace;
			}
			
			return result;
		}
		#endregion//OwnerInvocationHandler

		#region NonOwnerInvocationHandler
		private object NonOwnerInvocationHandler(object target, MethodBase method, object[] parameters) 
		{
			object result = null;

			try
			{
				if(method.Name.Equals("set_HotOrNot"))
				{
					result = method.Invoke(target, parameters);
				}
				else
				{
					throw new UnauthorizedAccessException("You are not permitted to update another's personal information!");
				}
			}
			catch(ApplicationException ex)
			{
				return ex.StackTrace;
			}
			
			return result;
		}
		#endregion//NonOwnerInvocationHandler
	}
}
